package com.skyblue.statemachine.parentchild;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineBuilder;
import org.springframework.stereotype.Component;

import java.util.Set;

@Component
public class ParentChildStateMachineBuilder {

    private final static String MACHINE_ID = "pcMachine";

    /**
     * 构建父子状态机
     */
    public StateMachine<String, String> build(BeanFactory beanFactory) throws Exception {
        StateMachineBuilder.Builder<String, String> builder = StateMachineBuilder.builder();

        builder.configureConfiguration().withConfiguration()
                .machineId(MACHINE_ID).beanFactory(beanFactory);

        builder.configureStates()
                .withStates().initial("父状态-0") // 配置父状态
                .states(Set.of("父状态-0", "父状态-1", "父状态-2", "父状态-3", "子状态-1-0", "子状态-1-1", "子状态-1-2", "子状态-1-3", "子状态-2-0", "子状态-2-1", "子状态-2-2"))
                .and().withStates().parent("父状态-1").initial("子状态-1-0") // 配置子状态
                .choice("子状态-1-0") // 定义选择节点，根据事件触发不同的目标状态
                .states(Set.of("子状态-1-0", "子状态-1-1", "子状态-1-2", "子状态-1-3"))
                .and().withStates().parent("父状态-2").initial("子状态-2-0") // 配置子状态
                .choice("子状态-2-0") // 定义选择节点，根据事件触发不同的目标状态
                .states(Set.of("子状态-2-0", "子状态-2-1", "子状态-2-2"))
                .and().withStates() // stateEntry状态进入时触发的动作，与@OnTransition区别是stateEntry仅关注状态进入，不涉及事件触发
                .stateEntry("父状态-2", context -> context.getStateMachine().sendEvent("事件-2 -> 2-0"))
                .and();

        builder.configureTransitions()
                .withExternal().source("父状态-0").target("父状态-1")
                .event("事件-0 -> 1").action((context) -> System.out.println("触发事件-0 -> 1"))
                .and().withExternal().source("父状态-1").target("子状态-1-0")
                .event("事件-1 -> 1-0").action((context) -> System.out.println("触发事件-1 -> 1-0"))
                .and().withChoice().source("子状态-1-0")
                .first("子状态-1-1", context -> false, context -> System.out.println("触发事件-1-1"))
                .then("子状态-1-2", context -> true, context -> System.out.println("触发事件-1-2"))
                .last("子状态-1-3", context -> System.out.println("触发事件-1-3"))
                .and().withExternal().source("子状态-1-1").target("父状态-2")
                .event("事件-1-1 -> 2").action((context) -> System.out.println("触发事件-1-1 -> 2"))
                .and().withExternal().source("子状态-1-2").target("父状态-2")
                .event("事件-1-2 -> 2").action((context) -> {
                    StateMachine<String, String> stateMachine = context.getStateMachine();
                    System.out.printf("\033[36;1m触发事件-1-2 -> 2，当前状态：%s\033[0m\n", stateMachine.getState());
                    stateMachine.sendEvent("事件-2 -> 2-0");
                    // ‌此时会有时序问题‌：Action执行时‌状态尚未更新‌。
                    // 1：当前转换的目标状态在action完成后才生效，若在action中立即触发依赖新状态的事件，可能因状态未同步而失败。
                    // 2：可能‌导致循环触发‌：若事件再次触发返回当前状态的转换，会形成无限循环。
                })
                .and().withExternal().source("子状态-1-3").target("父状态-2")
                .event("事件-1-3 -> 2").action((context) -> System.out.println("触发事件-1-3 -> 2"))
                .and().withExternal().source("父状态-2").target("子状态-2-0")
                .event("事件-2 -> 2-0").action((context) -> System.out.println("触发事件-2 -> 2-0"))
                .and().withChoice().source("子状态-2-0")
                .first("子状态-2-1", context -> false, context -> System.out.println("触发事件-2-1"))
                .last("子状态-2-2", context -> System.out.println("触发事件-2-2"));

        return builder.build();
    }

}